package org.streets.wicket;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import org.apache.tapestry5.ioc.services.ClassNameLocator;
import org.apache.wicket.Application;
import org.apache.wicket.Page;
import org.apache.wicket.Request;
import org.apache.wicket.RequestCycle;
import org.apache.wicket.Response;
import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.protocol.http.WebRequest;
import org.apache.wicket.protocol.http.WebResponse;
import org.apache.wicket.protocol.http.WicketFilter;
import org.apache.wicket.request.target.coding.HybridUrlCodingStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.streets.commons.util.ClassLoaderUtils;
import org.streets.commons.util.ClassUtils;
import org.streets.commons.util.StringUtils;
import org.streets.context.HiveConstants;
import org.streets.context.HiveRegistry;
import org.streets.context.definition.ContextDefinition;
import org.streets.context.definition.ModuleDefinition;
import org.streets.wicket.ioc.HiveComponentInjector;

public abstract class HiveWebApplication extends WebApplication {

    private final Logger LOG = LoggerFactory.getLogger(HiveWebApplication.class);
    
    private boolean injectable = false;
    
    protected HiveRegistry registry = null;
    
    private String contextPath = null;
    

	/**
	 * Covariant override for easy getting the current {@link WebApplication} without having to cast
	 * it.
	 */
	public static HiveWebApplication get()
	{
		Application application = Application.get();

		if (!(application instanceof HiveWebApplication)) {
			throw new HiveWicketException("The application attached to the current thread is not a " +
					HiveWebApplication.class.getSimpleName());
		}

		return (HiveWebApplication)application;
	}	
	
    /**
     * Initializes the filter using the {@link TapestryAppInitializer}. The application name is the capitalization of
     * the filter name (as specified in web.xml).
     */
    @Override 
    protected void init() {
    	
    	super.init();
    	
    	WicketFilter filter = getWicketFilter();

    	injectable = filter instanceof HiveWicketFilter;
    	
    	if (!injectable) return;
    	
    	
    	contextPath = ((HiveWicketFilter) getWicketFilter()).getHiveContext().root();
    	
    	registry = ((HiveWicketFilter) getWicketFilter()).getHiveContext().registry();    	
    	// classNameLocator
    	ClassNameLocator classNameLocator = registry.service(ClassNameLocator.class);
    	// mount all pages 
    	Set<String> pathSet = new HashSet<String>();
    	
    	String pattern = ((HiveWicketFilter)getWicketFilter()).getFilterPattern();
    	
    	Collection<ModuleDefinition> module_defs = registry.service(ContextDefinition.class).getModules();
    	
    	for (ModuleDefinition md : module_defs) {
    		
    		//如果不是声明要暴露的模块就跳过
    		if (md.getType() != 1) continue;
    		
    		Collection<String> pages = classNameLocator.locateClassNames(ClassUtils.getPackageName(md.getModuleClass())+".pages");    		
    		
    		for (String page : pages) {
    			
    			String p_n = ClassUtils.getShortClassName(page);
    			
    			if (p_n.endsWith("Page")) {    				
    				p_n = p_n.substring(0, p_n.lastIndexOf("Page"));    				
    			}
    			
    			Class<? extends Page> p_c = ClassLoaderUtils.loadClass(page);
    			
    			p_n = StringUtils.uncapitalize(p_n);//首字母小写
    			
    			// 加入自定义的Pattern
    			String path = (pattern == null ? "" : pattern) + md.getId() + "/" + p_n;
    			
    			if (!pathSet.contains(path)) {
	    			LOG.info("Mount ["+path+"] to "+p_c);
	    			mount(new HybridUrlCodingStrategy(path, p_c));
	    			pathSet.add(path); //去重
    			} else {
    				LOG.warn("Path : "+path+" has mounted already.");
    			}
    		}
    	}
    	// For PageClass field inject use
    	addComponentInstantiationListener(new HiveComponentInjector(registry));
    	    	
    	String charset = registry.symbolValue(HiveConstants.APPLICATION_CHARSET);
    	if (charset == null) {
            charset = "utf-8";
    	}
    	getMarkupSettings().setDefaultMarkupEncoding(charset);
    }
    /**
     * Get HiveRegistry to obtain service-point
     * 
     * @return
     */
    public HiveRegistry getRegistry() {
    	
    	return registry;
    }
    
	public String getContextPath() {
		return contextPath;
	}    
    
    @Override
    public String getConfigurationType() {
    	if (injectable) {
            return ((HiveWicketFilter)getWicketFilter()).applicationMode();
    	} else {
            return super.getConfigurationType();
    	}
    }
    
    @Override
    public RequestCycle newRequestCycle(final Request request, final Response response)
    {
    	if (injectable) {
    		return new HiveRequestCycle(this, (WebRequest)request, (WebResponse)response);
    	} else {
    		return super.newRequestCycle(request, response);
    	}		
    }
}
